<template>
  <div class="popup" @touchmove.stop.prevent>
    <div
      class="overlay"
      @click="clickOverlay"
      :style="[showOverlay, { transition: duration + 's' }]"
    ></div>
    <div
      class="panel"
      :class="'popup-panel--' + position"
      :style="[
        panelStyle,
        showPopup,
        {
          transform,
          transition: duration + 's',
        },
      ]"
    >
      <slot></slot>
    </div>
  </div>
</template>

<script>
export default {
  name: "Popup",
  props: {
    value: {
      type: Boolean,
      default: false,
    },
    // 面板样式
    styles: Object,
    // 动画时长，单位秒
    duration: {
      type: Number,
      default: 0.3,
    },
    // 弹出位置，默认居中弹出，可以设置为 top、bottom、left、right
    position: {
      type: String,
      default: "center",
    },
    // 是否在点击遮罩层后关闭
    clickOverlayClose: {
      type: Boolean,
      default: true,
    },
    // 是否启用缩放动画
    scaleAnimation: {
      type: Boolean,
      default: true,
    },
  },
  computed: {
    panelStyle() {
      return Object.assign(
        {
          height: "300px",
          background: "#fff",
        },
        this.styles
      );
    },
  },
  watch: {
    value(show) {
      let { position, panelStyle } = this;
      let { width, height } = panelStyle;
      this.resetPopupAnimation(width, height, position);

      if (show) {
        this.openPopup(position);
      } else {
        this.closePopup(position);
      }
    },
  },
  data() {
    return {
      showOverlay: {
        display: "none",
        opacity: 0,
      },
      showPopup: {
        opacity: 0,
        display: "none",
      },
      transform: "",
    };
  },
  methods: {
    // 打开弹窗
    openPopup(position) {
      this.showPopup = {};
      this.showOverlay = { opacity: 0 };

      if (position === "center") {
        this.showPopup = { opacity: 0 };
      }

      setTimeout(() => {
        if (position === "center") {
          if (this.scaleAnimation) {
            this.transform = `scale(1)`;
          }
        } else if (position === "left" || position === "right") {
          this.transform = `translateX(0)`;
        } else if (position === "bottom" || position === "top") {
          this.transform = `translateY(0)`;
        }
        this.$set(this.showOverlay, "opacity", 1);
        this.opened();
      }, 5);

      setTimeout(() => {
        this.showPopup = { opacity: 1, display: "block" };
      }, 100);
    },
    // 关闭弹窗
    closePopup(position) {
      this.$set(this.showOverlay, "opacity", 0);

      if (position === "center") {
        this.showPopup = { opacity: 0 };
      }

      setTimeout(() => {
        this.$set(this.showPopup, "display", "none");
        this.$set(this.showOverlay, "display", "none");
      }, this.duration * 1000);
    },
    // 重置弹窗动画
    resetPopupAnimation(width, height, position) {
      let tX = "";
      switch (position) {
        case "center":
          if (this.scaleAnimation) {
            tX = `scale(0)`;
          }
          break;
        case "left":
          tX = `translateX(-${width})`;
          break;
        case "right":
          tX = `translateX(${width})`;
          break;
        case "top":
          tX = `translateY(-${height})`;
          break;
        case "bottom":
          tX = `translateY(${height})`;
          break;
      }
      this.transform = tX;
    },
    // 打开弹出层且动画结束后触发
    opened() {
      setTimeout(() => {
        this.$emit("opened");
      }, this.duration * 1000);
    },
    // 点击遮罩层时触发
    clickOverlay() {
      if (this.clickOverlayClose) {
        this.$emit("clickOverlay");
        this.$emit("input", false);
        this.close();
      }
    },
    // 关闭弹出层时触发
    close() {
      this.$emit("close");
      this.closed();
    },
    // 关闭弹出层且动画结束后触发
    closed() {
      setTimeout(() => {
        this.$emit("closed");
      }, this.duration * 1000);
    },
  },
};
</script>

<style lang="scss" scoped>
$radius: 10px;

.popup {
  .overlay {
    width: 100%;
    height: 100%;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 9000;
    background-color: rgba($color: #000000, $alpha: 0.5);
  }

  .panel {
    width: 100%;
    position: fixed;
    z-index: 9001;

    &.popup-panel--center {
      width: 80%;
      left: 0;
      right: 0;
      top: 0;
      bottom: 0;
      margin: auto;
      border-radius: $radius;
      transition-timing-function: cubic-bezier(1, 0, 0, 1);
    }

    &.popup-panel--top {
      top: 0;
      left: 0;
      right: 0;
      border-radius: 0 0 $radius $radius;
    }

    &.popup-panel--bottom {
      bottom: 0;
      left: 0;
      right: 0;
      border-radius: $radius $radius 0 0;
    }

    &.popup-panel--left {
      width: 200px;
      height: 100% !important;
      top: 0;
      left: 0;
    }

    &.popup-panel--right {
      width: 200px;
      height: 100% !important;
      top: 0;
      right: 0;
    }
  }
}
</style>